﻿#include <iostream>
#include "threadpool.h"

void ThreadPool::setMode(PoolMode m) {
	mode = m;
}

void ThreadPool::cachedMode() {
	// 启动一个线程监视业务队列和线程池
	//std::thread([this] {
	//	}).detach();
	// 定期检查，加锁安全访问
	//std::this_thread::sleep_for(std::chrono::seconds(500));
	while (taskNum || threadVec.size() > initThreadSize)
	{
		std::unique_lock<std::mutex> lock(taskMutex);
		// 如果当前线程数 < 业务数，则增加线程数
		if (threadVec.size() < taskNum && threadVec.size() < maxThreadSize) {
			auto newThread = new Thread(std::bind(&ThreadPool::threadAlloc, this));
			threadVec.emplace_back(std::move(newThread));
			newThread->start();
			std::cout << "cached增加线程" << std::endl;
		}
		// 如果当前线程数 > 初始线程数，并且业务数 < 线程数，则销毁末尾线程
		if (threadVec.size() > initThreadSize && taskNum < threadVec.size()) {
			auto backThread = threadVec.back();
			threadVec.pop_back();
			delete backThread;
			std::cout << "cached安全销毁线程" << std::endl;
		}
	}
}

void ThreadPool::setTaskMax(int tm) {
	taskMaxNum = tm;
}

// 模拟线程分配给业务的过程：请求与成功
void ThreadPool::threadAlloc() {
	while (true)
	{
		std::shared_ptr<Task> task;
		{
			// 上锁
			std::unique_lock<std::mutex> lock(taskMutex);
			std::cout << std::this_thread::get_id() << " 线程请求分配业务" << std::endl;
			// 等待notEmpty
			while (taskQueue.size() <= 0)
			{
				taskNotEmpty.wait(lock);
			}
			std::cout << std::this_thread::get_id() << " 线程分配业务成功" << std::endl;
			// 取出第一个业务，业务队列里的业务减一
			task = taskQueue.front();
			taskQueue.pop();
			taskNum--;
			// 通知业务队列的其他业务继续
			if (taskQueue.size() > 0) {
				taskNotEmpty.notify_all();
			}
			// 通知可以新加入任务队列，因为取出了第一个所以未满
			taskNotFull.notify_all();
		}
		// 执行线程分配到的任务
		if (task) {
			task->run();
		}
	}
}

// 业务队列初始化
void ThreadPool::initTaskQueue(std::shared_ptr<Task> task, int tNum) {
	std::unique_lock<std::mutex> lock(taskMutex);
	for (int i = 0; i < tNum; ++i) {
		while (taskQueue.size() >= TASKMAXNUM) {
			// 业务队列没有空位且阻塞1s时，就判断为线程申请失败(防止死锁?)
			taskNotFull.wait_for(lock, std::chrono::seconds(1));
			std::cout << "业务队列没有空位且阻塞1s，判断为线程申请失败" << std::endl;
		}
		// 业务队列未满时，在末尾构造task，并条件变量通知队列不为空
		taskQueue.emplace(task);
		taskNum++;
		taskNotEmpty.notify_all();
	}
}

// 线程池的初始线程创建
void ThreadPool::start(int initSize) {
	initThreadSize = initSize;
	for (int i = 0; i < initThreadSize; ++i) {
		//auto thread = std::make_unique<Thread>(std::bind(&ThreadPool::threadFunc, this));
		//threadVec.emplace_back(thread.get());
		threadVec.emplace_back(new Thread(std::bind(&ThreadPool::threadAlloc, this)));
	}
	// 启动所有"线程"
	for (int i = 0; i < initThreadSize; ++i) {
		threadVec[i]->start();
	}
}

void Thread::start() {
	std::thread t(funtion);
	// 使得线程t不会在主线程结束后销毁
	t.detach();
}